using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
// https://zhuanlan.zhihu.com/p/266077243 注意图片的锚点 和 设置动态摇杆时背景的跟随阈值
public class MyJoyStick : MonoBehaviour, IPointerDownHandler, IDragHandler, IPointerUpHandler
{
    public enum JoyStickType
    {
        Fixed,
        Floating,
        Dynamic
    }
    // 摇杆类型
    public JoyStickType joyStickType;
    [SerializeField]
    // 控制器所在的画布
    private Canvas canvas;
    [SerializeField]
    public Camera _camera;
    // 用户输入
    public Vector2 input = Vector2.zero;
    private Vector2 center = new Vector2(0.5f, 0.5f);
    private Vector2 fixedPositon = Vector2.zero;

    [SerializeField]
    // 背景
    public RectTransform background = null;
    [SerializeField]
    // 摇杆矩形变化组件
    public RectTransform stickPoint = null;
    [SerializeField]
    // canvas的矩形变换组件
    private RectTransform baseRect = null;
    [SerializeField]
    // 摇杆死区
    private float deadZone = 0;
    public float DeadZone
    {
        get { return deadZone; }
        set
        {
            deadZone = Mathf.Abs(value);
        }
    }
    [SerializeField]
    public float MoveThreshold;

    void Start()
    {
        baseRect = GetComponent<RectTransform>();

        canvas = GetComponentInParent<Canvas>();
        // 背景锚点设置为自身的中心
        background.pivot = center;
        // 摇杆锚定到背景的中心
        stickPoint.anchorMin = center;
        stickPoint.anchorMax = center;
        stickPoint.pivot = center;
        stickPoint.anchoredPosition = Vector2.zero;
        // 背景固定在屏幕中的位置
        fixedPositon = background.anchoredPosition;
        setMode();
    }

    private void setMode()
    {
        if (joyStickType == JoyStickType.Fixed)
        {
            background.anchoredPosition = fixedPositon;
            background.gameObject.SetActive(true);
        }
        else
        {
            background.gameObject.SetActive(false);
        }
    }

    public void OnPointerDown(PointerEventData eventData)
    {
        if (joyStickType != JoyStickType.Fixed)
        {
            background.anchoredPosition = ScreenPointToAnchoredPosition(eventData.position);
            background.gameObject.SetActive(true);
        }
        // 触摸时开始拖动
        OnDrag(eventData);
    }

    public void OnDrag(PointerEventData eventData)
    {
        // 取得背景在屏幕坐标的位置
        Vector2 bgPos = Camera.main.WorldToScreenPoint(background.position);
        // 摇杆活动半径
        Vector2 radius = background.sizeDelta * 0.5f;
        // 摇杆实际输出向量的计算（给人物进行移动）
        // 屏幕空间下触点位置减去背景的位置就是最终移动的目标点相对于背景中心的位置向量
        // 活动半径*画布缩放系数得到屏幕空间下的活动半径
        // UI坐标 * 画布缩放 == 屏幕坐标
        // (eventData.position - bgPos) / radius 求出屏幕坐标下摇杆相对背景中心移动的向量
        // 将屏幕中的触点和background的距离映射到ui空间下实际的距离
        input = (eventData.position - bgPos) / (radius * canvas.scaleFactor);
        // 输入限制
        HandleInput(input.magnitude, input.normalized, radius, _camera);
        // 改变摇杆相对于中心锚点的UI坐标下的位置（给玩家的UI反馈）
        stickPoint.anchoredPosition = input * radius;
    }

    private void HandleInput(float magnitude, Vector2 normalized, Vector2 radius, Camera camera)
    {
        if (magnitude > DeadZone)
        {
            if (magnitude > 1)
            {
                input = normalized;
            }
        }
        else
        {
            input = Vector2.zero;
        }

        if (joyStickType == JoyStickType.Dynamic && magnitude > MoveThreshold)
        {
            // 动态摇杆即摇杆背景也跟着摇杆移动，初始化时把背景的锚点也定在了canvas的中心
            Vector2 diff = normalized * (magnitude - MoveThreshold) * radius;
            background.anchoredPosition += diff;
        }
    }

    public void OnPointerUp(PointerEventData eventData)
    {
        if (joyStickType != JoyStickType.Fixed)
        {
            background.gameObject.SetActive(false);
        }
        input = Vector2.zero;
        stickPoint.anchoredPosition = Vector2.zero;
    }
    // 屏幕坐标转化为UI坐标
    private Vector2 ScreenPointToAnchoredPosition(Vector2 screenPosition)
    {
        Vector2 localPoint = Vector2.zero;
        RectTransformUtility.ScreenPointToLocalPointInRectangle(baseRect, screenPosition, _camera, out localPoint);
        return localPoint;
    }
}
